package crp.services.api.graphql.loaders;

import com.qwlabs.jackson.Jackson;
import com.qwlabs.lang.C2;
import crp.core.user.domain.models.UserEntity;
import crp.core.user.domain.repositories.UserRepository;
import crp.core.workflow.app.WorkflowService;
import crp.core.workflow.domain.models.WorkflowInstanceEntity;
import crp.core.workflow.domain.models.WorkflowModelEntity;
import crp.core.workflow.domain.services.WorkflowInstanceSearcher;
import crp.services.api.graphql.models.WorkflowInstanceContextPayload;
import crp.services.api.graphql.models.WorkflowInstancePayload;
import crp.services.api.graphql.models.WorkflowModelPayload;
import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Source;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@GraphQLApi
@RequestScoped
public class WorkflowInstancePayloadLoader {
    private final WorkflowService workflowService;
    private final WorkflowInstanceSearcher workflowInstanceSearcher;
    private final UserRepository userRepository;

    @Inject
    public WorkflowInstancePayloadLoader(WorkflowService workflowService,
                                         WorkflowInstanceSearcher workflowInstanceSearcher,
                                         UserRepository userRepository) {
        this.workflowService = workflowService;
        this.workflowInstanceSearcher = workflowInstanceSearcher;
        this.userRepository = userRepository;
    }

    public List<@NotNull WorkflowModelPayload> model(@Source List<WorkflowInstancePayload> instances) {
        Map<String, String> modelInstanceIds = C2.map(instances, WorkflowInstancePayload::getModelId,
                WorkflowInstancePayload::getId);
        Map<String, WorkflowModelPayload> models =
                C2.map(workflowService.modelSearcher().findByIds(modelInstanceIds.keySet()),
                        WorkflowModelEntity::getId, model -> WorkflowModelPayload.of(model,
                                modelInstanceIds.get(model.getId())));
        return C2.list(instances, instance -> models.get(instance.getModelId()));
    }

    public List<@NotNull WorkflowInstanceContextPayload> context(@Source List<WorkflowInstancePayload> instances) {
        Set<String> ids = C2.set(instances, WorkflowInstancePayload::getId);
        List<WorkflowInstanceEntity> instancesEntities = workflowInstanceSearcher.byIds(ids).collect(Collectors.toList());
        Map<String, UserEntity> userMap = C2.map(
                userRepository.findByIds(C2.set(instancesEntities, item -> item.getContext().getSubmittedBy())),
                UserEntity::getId, Function.identity());
        Map<String, WorkflowInstanceContextPayload> instanceContextPayloadMap =
                C2.map(instancesEntities, WorkflowInstanceEntity::getId,
                        instance -> WorkflowInstanceContextPayload.builder()
                                .topic(instance.getContext().getTopic())
                                .externalInfo(workflowInstanceSearcher.externalInfo(instance.getContext().getExternalId(),
                                        instance.getContext().getTopic()))
                                .formAttributes(Jackson.write(instance.getContext().getFormAttributes()).orElse(""))
                                .submittedBy(userMap.get(instance.getContext().getSubmittedBy()).getName())
                                .build());
        return C2.list(instances, instance -> instanceContextPayloadMap.get(instance.getId()));
    }


}
